import {getLanguageById, getLocale} from "../../i18n/i18n";
import {
    createFetchParams,
    formatStr,
    getObjByRule,
    importComponent,
    isArray,
    isFunction,
    validDataset,
    validField,
    validFieldUn
} from "../utils";
import {coreDispatch} from "../utils/StoreUtil";
import {previewFile} from "./PreviewService";
import {AxiosDownload} from "./HttpService";
import {getUserInfo} from "./SecurityService.tsx";
import {showMessage} from "../reducer/MsgReducer.tsx";

// 解析操作流程字符串的正则
let flowReg: any = /([^\.])\.([^\,\(]+)(\(([^\)]*)\))?(\s*\,\s*)?/g;

const ds: Function = async function (name: string, ...args: any[]) {
    // @ts-ignore
    let val = this.dataSource[name];
    if (isFunction(val)) {
        // @ts-ignore
        return await val.apply(this, args)
    }
    return val;
}


// btnFlow执行方法对象
let flowFunMap: any = {};

// g流程    获取数据流程
flowFunMap.g = {
    ds,
    asyncDs: ds
};

// v流程    数据校验流程
flowFunMap.v = {
    ds,
    asyncDs: ds,
    /**
     * 确定获取到的数组中至多只有一个元素
     * @param isNull 是否允许没有元素，默认false
     * @returns {null|*}
     */
    isRow: function (isNull: boolean = false) {
        if (!isNull && !this.flowData.length) {
            throw new Error(getLanguageById("pSelectOne"))
        } else if (this.flowData.length > 1) {
            throw new Error(getLanguageById("pSelectOnlyOne"))
        }
        return this.flowData;
    },
    /**
     * 获取到的数组中必须有一个或多个元素
     */
    isRows: function (isNull: boolean = false) {
        if (!isNull && !this.flowData.length) {
            throw new Error(getLanguageById("pSelectLeastOne"))
        }
        return this.flowData;
    },
    /*
    * 判断是发布
    */
    isReleases: function () {
        if (!validField(this.flowData, {lastReleaseStatusId: null})) {
            throw new Error(getLanguageById("publishNoOpt"))
        }
        return this.flowData;
    },
    /*
    * 判断是否流程中
    */
    isFlows: function (flowKey: string = "inFlow") {
        if (!validField(this.flowData, {[flowKey]: [null, 0]})) {
            throw new Error(getLanguageById("notUpdateIsFlow"))
        }
        return this.flowData;
    },
    /*
    * 判断是否签出并且签出，用户是当前用户
    */
    isSignOuts: function (isOut: boolean = true, isCurUser: boolean = false) {
        const {id}: { id: string } = getUserInfo();
        let data: any[] = isArray(this.flowData) ? this.flowData : [this.flowData];
        for (let i in data) {
            let item: any = data[i];
            if (isOut) {
                if (item.checkedOut && !(isCurUser && item.checkedOutUserId === id)) {
                    throw new Error(getLanguageById("checkOutNoUser", {user: getLocale(item.checkedOutUserStrCn, item.checkedOutUserStrCn)}))
                }
            } else {
                if (!item.checkedOut) {
                    throw new Error(getLanguageById("unCheckOut"))
                } else if (item.checkedOut && item.checkedOutUserId !== id) {
                    throw new Error(getLanguageById("checkOutNoUser", {user: getLocale(item.checkedOutUserStrCn, item.checkedOutUserStrCn)}))
                }
            }
        }

        return this.flowData;
    },
    /**
     * 校验对象
     * @param validObj 校验规则对象
     * @param i18nId 错误提示多语言数据中的 key
     * @returns {boolean} 错误: false, 正确: true
     */
    validField: function (validObj: any, i18nId: string) {
        if (!validField(this.flowData, validObj)) {
            throw new Error(getLanguageById(i18nId || ""))
        }
        return this.flowData;
    },
    unValidField: function (validObj: any, i18nId: string) {
        if (validFieldUn(this.flowData, validObj)) {
            throw new Error(getLanguageById(i18nId))
        }
        return this.flowData;
    },
    /*
     * 校验选中对象是否是数据集
     */
    isDataset: function (typeField: string, isDataset: boolean = true, i18nId: string) {
        if (isDataset && !validDataset(this.flowData, typeField)) {
            throw new Error(getLanguageById(i18nId || "pSelectDataset"))
        } else if (!isDataset && validDataset(this.flowData, typeField)) {
            throw new Error(getLanguageById(i18nId || "pUnSelectDataset"))
        }
        return this.flowData;
    }
};

// f流程    操作执行流程
flowFunMap.f = {
    ds,
    asyncDs: ds,
    show: async function (comPath: string, props: any = {}, modalProps: any = {}) {
        props.flowData = this.getFlowResult("g");
        props.dataSource = this.dataSource;
        if (props.defaultValue) {
            props.defaultValue = getObjByRule(props, props.defaultValue);
        }
        let Com = await importComponent(comPath);
        if (!Com) {
            throw new Error(`${getLanguageById("errorComPath")}'${comPath}'`)
        }
        return new Promise((resolve, reject) => {
            let menu = this.menuData;
            props.menuId = menu.id;
            coreDispatch("modalReducer/createModal", {
                key: menu["data-menu-id"],
                modalProps: {
                    title: menu.title,
                    ...modalProps,
                    okText: getLanguageById(modalProps.okText || "determine"),
                    cancelText: getLanguageById(modalProps.cancelText || "cancel")
                },
                component: Com,
                comProps: props,
                onFinish: (resultData: any) => {
                    // 如果对话框没有返回数据则认定操作失败，后续操作取消
                    if (resultData) {
                        resolve(resultData)
                    } else {
                        reject(resultData)
                    }
                }
            });
        })
    },
    preview: function (renderProps: any) {
        let [row] = this.getFlowResult("g");
        previewFile(row, {
            ...renderProps
        });
    },
    download: function (renderProps: any) {
        renderProps.flowData = this.getFlowResult("g");
        renderProps.dataSource = this.dataSource;
        const {url, params = {}}: { url: string, params: any } = createFetchParams(renderProps);
        return AxiosDownload(url, params, () => {
        }, renderProps.method);
    }
};

// c流程    回调操作流程
flowFunMap.c = {
    ds,
    asyncDs: ds,
    removeAllCopyRows: () => {
        coreDispatch("copyReducer/updateCopyList", []);
    }
};

// @ts-ignore
const expandFlowFunMap: Function = (tag: string, expandFun: object) => {
    flowFunMap[tag] = {
        ...flowFunMap[tag],
        ...expandFun
    };
}

const BtnFlow: Function = (target: any, dataSource: any, menuData: any) => {
    const BtnFlowService: object = {
        target,
        dataSource,
        menuData,
        flowData: null,
        flowResult: {},
        allFlow: [],
        init: function () {
            let operateStr: string = formatStr(menuData.operate, {ds: dataSource}, /\$\{(ds\.[^\}]*)\}/g);
            let arr = null;
            do {
                arr = flowReg.exec(operateStr);
                if (arr != null) {
                    // 正则匹配之后是类似这样的数组
                    // ["f.edit('baidu', '12')", "f", "edit", "('baidu', '12')", "'baidu', '12'"]
                    // 加入到所有执行对象中
                    // @ts-ignore
                    this.allFlow.push({
                        // 名称
                        name: arr[2],
                        // 参数数组
                        params: arr[4] ? eval("[" + arr[4] + "]") : [],
                        // 标识
                        tag: arr[1]
                    });
                }
            } while (arr != null);

        },
        getFlowResult: function (flowName: string) {
            // @ts-ignore
            return this.flowResult[flowName];
        },
        deferredExecute: async function (options: any = {}) {
            let {tags, showMsg, noAsync} = options;
            // 使用原始循环确保await执行
            try {
                // @ts-ignore
                for (let b: number = 0; b < this.allFlow.length; b++) {
                    // @ts-ignore
                    let curFlow = this.allFlow[b],
                        {tag, params, name} = curFlow;

                    // 如果不执行异步方法开启 发现是异步方法则停止整个流程
                    if (!tags || tags.indexOf(tag) !== -1) {
                        if (noAsync && name.startsWith("async")) {
                            return;
                        }
                        let fun = flowFunMap[tag] && flowFunMap[tag][name];
                        if (!isFunction(fun)) {
                            throw new Error(`没有定义的${tag}.${name}流程`);
                        }
                        // log(`start ${tag}.${funParam.name}`)
                        // @ts-ignore
                        this.flowData = await fun.apply(this, params);

                        // 记录每一段流程的返回值
                        // @ts-ignore
                        this.flowResult[tag] = this.flowData;
                        // log(`end ${tag}.${funParam.name}`)
                    }
                }
            } catch (e: any) {
                if (showMsg === false) {
                    throw e;
                }
                if (e) {
                    if (e.name === "Error") {
                        showMessage({
                            type: "warning",
                            msg: e.message
                        })
                        return;
                    } else if (e.name === "AppError") {
                        // message.warning(intl.formatMessage({ id: e.message }));
                        return;
                    }
                    throw e;

                }
            }
        },
        flow: async function (options: any) {
            // @ts-ignore
            await this.init();
            // @ts-ignore
            await this.deferredExecute(options);
        }

    }
    return BtnFlowService
}

export {
    BtnFlow,
    expandFlowFunMap
};